
#ifndef __LINK32FA016BX_H__
#define __LINK32FA016BX_H__

#include <stddef.h>

#ifdef __cplusplus
#define LINK32FA016BX_BEGIN_DECLS extern "C" {
#define LINK32FA016BX_END_DECLS   }
#else
#define LINK32FA016BX_BEGIN_DECLS
#define LINK32FA016BX_END_DECLS
#endif

LINK32FA016BX_BEGIN_DECLS

/** @addtogroup link32
  * @{
  */


/** @addtogroup link32_soc
  * @{
  */


/** @addtogroup Configuration_of_NMSIS
  * @{
  */

/** \brief SoC Download mode definition */
typedef enum {
    DOWNLOAD_MODE_FLASH = 0,            /*!< Flash download mode */
    DOWNLOAD_MODE_SRAM = 1,              /*!< ilm download mode */
    DOWNLOAD_MODE_MAX,
} DownloadMode_Type;

/* Simulation mode macros */
#define SIMULATION_MODE_XLSPIKE   0     /*!< xlspike simulation mode */
#define SIMULATION_MODE_QEMU      1     /*!< qemu simulation mode */


/* =========================================================================================================================== */
/* ================                                Interrupt Number Definition                                ================ */
/* =========================================================================================================================== */

typedef enum IRQn {
    /* =======================================  Vectored Interrupt Numbers  ======================================== */

    Reserved0_IRQn            =   0,              /*!<  Internal reserved */
    Reserved1_IRQn            =   1,              /*!<  Internal reserved */
    Reserved2_IRQn            =   2,              /*!<  Internal reserved */
    MsipIRQn                  =   3,              /*!<  Machine SW interrupt */
    Reserved4_IRQn            =   4,              /*!<  Internal reserved */
    Reserved5_IRQn            =   5,              /*!<  Internal reserved */
    Reserved6_IRQn            =   6,              /*!<  Internal reserved */
    Mtip_IRQn                 =   7,              /*!<  Machine Timer Interrupt */
    Reserved8_IRQn            =   8,              /*!<  Internal reserved */
    Reserved9_IRQn            =   9,              /*!<  Internal reserved */
    Reserved10_IRQn           =  10,              /*!<  Internal reserved */
    Meip_IRQn                 =  11,              /*!<  Machine External Interrupt(PLIC) */
    Reserved12_IRQn           =  12,              /*!<  Internal reserved */
    Reserved13_IRQn           =  13,              /*!<  Internal reserved */
    Reserved14_IRQn           =  14,              /*!<  Internal reserved */
    Reserved15_IRQn           =  15,              /*!<  Internal reserved */
    UARTX_IRQn                =  16,              /*!<  UARTX interrupt */
    RTC_IRQn                  =  17,              /*!<  RTC   interrupt */
    IWDT_IRQn                 =  18,              /*!<  IWDT  interrupt */
    WWDT_IRQn                 =  19,              /*!<  WWDT  interrupt */
    Reserved20_IRQn           =  20,              /*!<  Internal reserved */
    Reserved21_IRQn           =  21,              /*!<  Internal reserved */
    Reserved22_IRQn           =  22,              /*!<  Internal reserved */
    Reserved23_IRQn           =  23,              /*!<  Internal reserved */
    Reserved24_IRQn           =  24,              /*!<  Internal reserved */
    Reserved25_IRQn           =  25,              /*!<  Internal reserved */
    Reserved26_IRQn           =  26,              /*!<  Internal reserved */
    Reserved27_IRQn           =  27,              /*!<  Internal reserved */
    Reserved28_IRQn           =  28,              /*!<  Internal reserved */
    Reserved29_IRQn           =  29,              /*!<  Internal reserved */
    Reserved30_IRQn           =  30,              /*!<  Internal reserved */
    NMI_IRQn                  =  31,              /*!<  Internal reserved */
    VEC_INT_MAX,

} IRQn_Type;

typedef enum PLIC_IRQn {
    /* =======================================  PLIC Interrupt Numbers  ======================================== */
    GPIO0_IRQn            =   1,              /*!<  GPIO0 interrupt*/
    GPIO1_IRQn            =   2,              /*!<  GPIO1 interrupt*/
    GPIO2_IRQn            =   3,              /*!<  GPIO2 interrupt*/
    GPIO3_IRQn            =   4,              /*!<  GPIO3 interrupt*/
    PLIC_INT_MAX,
} PLIC_IRQn_Type;


/* =========================================================================================================================== */
/* ================                                  Exception Code Definition                                ================ */
/* =========================================================================================================================== */

typedef enum EXCn {
    InsUnalign_EXCn          =   0,              /*!<  Instruction address misaligned */
    InsAccFault_EXCn         =   1,              /*!<  Instruction access fault */
    IlleIns_EXCn             =   2,              /*!<  Illegal instruction */
    Break_EXCn               =   3,              /*!<  Beakpoint */
    LdAddrUnalign_EXCn       =   4,              /*!<  Load address misaligned */
    LdFault_EXCn             =   5,              /*!<  Load access fault */
    StAddrUnalign_EXCn       =   6,              /*!<  Store or AMO address misaligned */
    StAccessFault_EXCn       =   7,              /*!<  Store or AMO access fault */
    UmodeEcall_EXCn          =   8,              /*!<  Environment call from User mode */
    SmodeEcall_EXCn          =   9,              /*!<  Environment call from S-mode */
    MmodeEcall_EXCn          =  11,              /*!<  Environment call from Machine mode */
    InsPageFault_EXCn        =  12,              /*!<  Instruction page fault */
    LdPageFault_EXCn         =  13,              /*!<  Load page fault */
    StPageFault_EXCn         =  15,              /*!<  Store or AMO page fault */
} EXCn_Type;

/* =========================================================================================================================== */
/* ================                           Processor and Core Peripheral Section                           ================ */
/* =========================================================================================================================== */


//#define __ECLIC_PRESENT           1                     /*!< Set to 1 if ECLIC is present */
//#define __ECLIC_BASEADDR          0xD2000000UL          /*!< Set to ECLIC baseaddr of your device */
//
//#define __ECLIC_INTCTLBITS        4                     /*!< Set to 1 - 8, the number of hardware bits are actually implemented in the clicintctl registers. */
//#define __ECLIC_INTNUM            86                    /*!< Set to 1 - 1005, the external interrupt number of ECLIC Unit */
//#define __SYSTIMER_PRESENT        1                     /*!< Set to 1 if System Timer is present */
//#define __SYSTIMER_BASEADDR       0xD1000000UL          /*!< Set to SysTimer baseaddr of your device */

#define __CLINT_PRESENT 1
#define __CLINT_BASEADDR 0xE1000000
#define __PLIC_PRESENT  1
#define __PLIC_BASEADDR  0xE2000000
#define __PLIC_INTNUM   32
#define __UARTX_PRESENT 1
#define __UARTX_BASEADDR 0xE3000000


/*!< Set to 0, 1, or 2, 0 not present, 1 single floating point unit present, 2 double floating point unit present */
#define __FPU_PRESENT             0

#define __DSP_PRESENT             0                     /*!< Set to 1 if DSP is present */
#define __PMP_PRESENT             1                     /*!< Set to 1 if PMP is present */
#define __PMP_ENTRY_NUM           8                     /*!< Set to 8 or 16, the number of PMP entries */
#define __ICACHE_PRESENT          0                     /*!< Set to 1 if I-Cache is present */
#define __DCACHE_PRESENT          0                     /*!< Set to 1 if D-Cache is present */
#define __INC_INTRINSIC_API       0                     /*!< Set to 1 if intrinsic api header files need to be included */
#define __Vendor_SysTickConfig    0                     /*!< Set to 1 if different SysTick Config is used */
#define __Vendor_EXCEPTION        0                     /*!< Set to 1 if vendor exception hander is present */

/** @} */ /* End of group Configuration_of_NMSIS */



#include <nmsis_core.h>                         /*!< ibex processor and core peripherals */
#include "system_link32fa016bx.h"               /*!< link32 System */


/* ========================================  Start of section using anonymous unions  ======================================== */
#if   defined (__GNUC__)
/* anonymous unions are enabled by default */
#else
#warning Not supported compiler type
#endif


// The TIMER frequency is just the RTC frequency
#define SOC_TIMER_FREQ     5000000  //LXTAL_VALUE units MHz

/* enum definitions */
typedef enum {
    DISABLE = 0,
    ENABLE = !DISABLE
} EventStatus, ControlStatus;

typedef enum {
    FALSE = 0,
    TRUE = !FALSE
} BOOL;

typedef enum {
    RESET = 0,
    SET = 1,
    MAX = 0X7FFFFFFF
} FlagStatus;

typedef enum {
    ERROR = 0,
    SUCCESS = !ERROR
} ErrStatus;

/* =========================================================================================================================== */
/* ================                            Device Specific Peripheral Section                             ================ */
/* =========================================================================================================================== */


/** @addtogroup Device_Peripheral_peripherals
  * @{
  */

/****************************************************************************
 * Platform definitions
 *****************************************************************************/





/* ToDo: add here your device specific peripheral access structure typedefs
         following is an example for Systick Timer*/

/* =========================================================================================================================== */
/* ================                                            SysTick Timer                                            ================ */
/* =========================================================================================================================== */

/*@}*/ /* end of group nuclei_soc_Peripherals */


/* =========================================  End of section using anonymous unions  ========================================= */
#if defined (__GNUC__)
/* anonymous unions are enabled by default */
#else
#warning Not supported compiler type
#endif


/* =========================================================================================================================== */
/* ================                          Device Specific Peripheral Address Map                           ================ */
/* =========================================================================================================================== */


/* ToDo: add here your device peripherals base addresses
         following is an example for timer */
/** @addtogroup Device_Peripheral_peripheralAddr
  * @{
  */
///* main flash and SRAM memory map */
//#define FLASH_BASE            ((uint32_t)0x08000000U)        /*!< main FLASH base address          */
//#define SRAM_BASE             ((uint32_t)0x20000000U)        /*!< SRAM0 base address               */
//#define OB_BASE               ((uint32_t)0x1FFFF800U)        /*!< OB base address                  */
//#define DBG_BASE              ((uint32_t)0xE0042000U)        /*!< DBG base address                 */
//#define EXMC_BASE             ((uint32_t)0xA0000000U)        /*!< EXMC register base address       */
//
///* peripheral memory map */
#define APB0_BUS_BASE         ((uint32_t)0x40000000U)        /*!< apb0 base address                */
#define APB1_BUS_BASE         ((uint32_t)0x40800000U)        /*!< apb1 base address                */
#define AHB_BUS_BASE          ((uint32_t)0x50000000U)        /*!< ahb  base address                */

#define SYSCFG_BASE           (APB0_BUS_BASE + 0x00000000U)  /*!< SYSCFG base address                 */
#define PMU_BASE              (APB0_BUS_BASE + 0x00010000U)  /*!< PMU base address                 */
#define RTC_BASE              (APB0_BUS_BASE + 0x00020000U)  /*!< RTC base address                 */
#define WWDG_BASE             (APB0_BUS_BASE + 0x00030000U)  /*!< WWDG base address                 */
#define IWDG_BASE             (APB0_BUS_BASE + 0x00040000U)  /*!< IWDG base address                 */
#define PWM0_BASE             (APB0_BUS_BASE + 0x00050000U)  /*!< PWM0 base address                 */
#define PWM1_BASE             (APB0_BUS_BASE + 0x00060000U)  /*!< PWM1 base address                 */
#define SPIH0_BASE            (APB0_BUS_BASE + 0x00070000U)  /*!< SPIH0 base address                 */
#define SPIH1_BASE            (APB0_BUS_BASE + 0x00080000U)  /*!< SPIH1 base address                 */
#define I2C0_BASE             (APB0_BUS_BASE + 0x00090000U)  /*!< I2C0 base address                 */
#define I2C1_BASE             (APB0_BUS_BASE + 0x000A0000U)  /*!< I2C1 base address                 */
#define UART0_BASE            (APB0_BUS_BASE + 0x000B0000U)  /*!< UART0 base address                 */
#define UART1_BASE            (APB0_BUS_BASE + 0x000C0000U)  /*!< UART1 base address                 */
#define SPID0_BASE            (APB0_BUS_BASE + 0x000D0000U)  /*!< SPID0 base address                 */
#define SPID1_BASE            (APB0_BUS_BASE + 0x000E0000U)  /*!< SPID1 base address                 */
#define DMA_BASE              (APB0_BUS_BASE + 0x000F0000U)  /*!< DMA base address                 */


#define GPIO_BASE             (AHB_BUS_BASE  + 0x00000000U)  /*!< GPIO base address                 */
#define RCU_BASE              (AHB_BUS_BASE  + 0x00070000U)  /*!< RCU base address                 */
#define FMC_BASE              (AHB_BUS_BASE  + 0x00080000U)  /*!< FMC base address                 */


/** @} */ /* End of group Device_Peripheral_peripheralAddr */


/* =========================================================================================================================== */
/* ================                                  Peripheral declaration                                   ================ */
/* =========================================================================================================================== */

/* Macros for memory access operations */
#define _REG8P(p, i)                        ((volatile uint8_t *) ((uintptr_t)((p) + (i))))
#define _REG16P(p, i)                       ((volatile uint16_t *) ((uintptr_t)((p) + (i))))
#define _REG32P(p, i)                       ((volatile uint32_t *) ((uintptr_t)((p) + (i))))
#define _REG64P(p, i)                       ((volatile uint64_t *) ((uintptr_t)((p) + (i))))
#define _REG8(p, i)                         (*(_REG8P(p, i)))
#define _REG16(p, i)                        (*(_REG16P(p, i)))
#define _REG32(p, i)                        (*(_REG32P(p, i)))
#define _REG64(p, i)                        (*(_REG64P(p, i)))
#define REG8(addr)                          _REG8((addr), 0)
#define REG16(addr)                         _REG16((addr), 0)
#define REG32(addr)                         _REG32((addr), 0)
#define REG64(addr)                         _REG64((addr), 0)

/* Macros for address type convert and access operations */
#define ADDR16(addr)                        ((uint16_t)(uintptr_t)(addr))
#define ADDR32(addr)                        ((uint32_t)(uintptr_t)(addr))
#define ADDR64(addr)                        ((uint64_t)(uintptr_t)(addr))
#define ADDR8P(addr)                        ((uint8_t *)(uintptr_t)(addr))
#define ADDR16P(addr)                       ((uint16_t *)(uintptr_t)(addr))
#define ADDR32P(addr)                       ((uint32_t *)(uintptr_t)(addr))
#define ADDR64P(addr)                       ((uint64_t *)(uintptr_t)(addr))

/* Macros for Bit Operations */
#if __riscv_xlen == 32
#define BITMASK_MAX                         0xFFFFFFFFUL
#define BITOFS_MAX                          31
#else
#define BITMASK_MAX                         0xFFFFFFFFFFFFFFFFULL
#define BITOFS_MAX                          63
#endif

// BIT/BITS only support bit mask for __riscv_xlen
// For RISC-V 32 bit, it support mask 32 bit wide
// For RISC-V 64 bit, it support mask 64 bit wide
#define BIT(ofs)                            (0x1UL << (ofs))
#define BITS(start, end)                    ((BITMASK_MAX) << (start) & (BITMASK_MAX) >> (BITOFS_MAX - (end)))
#define GET_BIT(regval, bitofs)             (((regval) >> (bitofs)) & 0x1)
#define SET_BIT(regval, bitofs)             ((regval) |= BIT(bitofs))
#define CLR_BIT(regval, bitofs)             ((regval) &= (~BIT(bitofs)))
#define FLIP_BIT(regval, bitofs)            ((regval) ^= BIT(bitofs))
#define WRITE_BIT(regval, bitofs, val)      CLR_BIT(regval, bitofs); ((regval) |= ((val) << bitofs) & BIT(bitofs))
#define CHECK_BIT(regval, bitofs)           (!!((regval) & (0x1UL<<(bitofs))))
#define GET_BITS(regval, start, end)        (((regval) & BITS((start), (end))) >> (start))
#define SET_BITS(regval, start, end)        ((regval) |= BITS((start), (end)))
#define CLR_BITS(regval, start, end)        ((regval) &= (~BITS((start), (end))))
#define FLIP_BITS(regval, start, end)       ((regval) ^= BITS((start), (end)))
#define WRITE_BITS(regval, start, end, val) CLR_BITS(regval, start, end); ((regval) |= ((val) << start) & BITS((start), (end)))
#define CHECK_BITS_ALL(regval, start, end)  (!((~(regval)) & BITS((start), (end))))
#define CHECK_BITS_ANY(regval, start, end)  ((regval) & BITS((start), (end)))

#define BITMASK_SET(regval, mask)           ((regval) |= (mask))
#define BITMASK_CLR(regval, mask)           ((regval) &= (~(mask)))
#define BITMASK_FLIP(regval, mask)          ((regval) ^= (mask))
#define BITMASK_CHECK_ALL(regval, mask)     (!((~(regval)) & (mask)))
#define BITMASK_CHECK_ANY(regval, mask)     ((regval) & (mask))

#include "link32fa016bx_rcu.h"
#include "link32fa016bx_spih.h"
#include "link32fa016bx_gpio.h"
#include "link32fa016bx_sfc.h"
#include "sfc_gd32wq.h"

// Interrupt Numbers
//#define SOC_ECLIC_NUM_INTERRUPTS    86
//#define SOC_ECLIC_INT_GPIO_BASE     19


// Interrupt Handler Definitions
#define SOC_MTIMER_HANDLER          TrapEntry_mtip
#define SOC_SOFTINT_HANDLER         TrapEntry_msip

#define NUM_GPIO 64

extern uint32_t get_cpu_freq(void);

/**
 *  \brief      delay a time in milliseconds
 *  \param[in]  count: count in milliseconds
 *  \param[out] none
 *  \retval     none
 */
extern void delay_1ms(uint32_t count);


/** @} */ /* End of group link32_soc */

/** @} */ /* End of group link32 */

LINK32FA016BX_END_DECLS

#endif  /* __LINK32FA016BX_SOC_H__ */
